package org.springonrails.template;

import java.io.File;
import java.io.FileWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springonrails.RailsException;
import org.springonrails.model.AppConfig;
import org.springonrails.model.Entity;
import org.springonrails.util.StringUtils;
/**
 * 
 * @author Sunny Liu
 *
 */
public class BuiltInFreeMarkerSourceGenerator implements SourceGenerator {

	private static Log  log = LogFactory.getLog(BuiltInFreeMarkerSourceGenerator.class);
	public final static String GROUPID  = "groupId";
	public final static String ARTIFACTID = "artifactId";
	public final static String VERSION = "version";
	public final static String OUTPUT_DIRECTORY = "outputDirectory";
	
	public final static String DEFAULT_GROUPID  = "org.springonrails.demo";
	public final static String DEFAULT_OUTPUT_DIR = "target";
	public final static String DEFAULT_ARTIFACTID = "demo";
	public final static String DEFAULT_VERSION = "1.0.0-SNAPSHOT";
	
	private String groupId                     = null;
	private String outputDir                   = null;
	private String artifactId                  = null;
	private Properties properties;
	private List<Entity> entities;
	private AppConfig appConfig                = null;
	private String version = null;
	
	public BuiltInFreeMarkerSourceGenerator(Properties properties)
	{
		this.properties = properties;
	}
	
	public void generateSource(List<Entity> entities) throws RailsException
	{
		if(log.isInfoEnabled()) log.info("Start genenrating source.");
		if(log.isInfoEnabled()) log.info("Loading configuration.");		
		this.appConfig = new AppConfig(getOutputDirectory(), getArtifactId(), getGroupId(), getProperties());
		this.entities = entities;		
		if(log.isInfoEnabled()) log.info("Loading templates.");		
		BuiltInTemplateRegistry registry = new BuiltInTemplateRegistry(appConfig);
		List<TemplateDef> templates = registry.getTemplateList();
		for (TemplateDef templateDef : templates) 
		{
			try{
				genSource(templateDef, entities);
			}catch(Exception ex){
				throw new RailsException("Failed to process template.", ex);
			}			
		}		
		if(log.isInfoEnabled()) log.info("Mission complished.");	
		
	}
	
	protected void genSource(TemplateDef templateDef, List<Entity> entities) throws Exception
	{
		Map<String, Object> map = getFreeMarkerMap();
		if(!templateDef.getOutputDirectory().exists())templateDef.getOutputDirectory().mkdirs();
		if(templateDef.isApplyToEachEntity())
		{
			for (Entity entity : entities) {
				String fileName = templateDef.getSourceFileNamePrefix()
				+ entity.getJavaName()
				+ templateDef.getSourceFileNameSuffix()
				+ templateDef.getSourceFileNameExtension();				
				File javaSourceFile = new File(templateDef.getOutputDirectory(), fileName);				
				log.info("Generating file " + javaSourceFile.getCanonicalPath());
				map.put("entity", entity);				
				FileWriter out = null;			 
				try {
					out = new FileWriter(javaSourceFile);
					((BuiltInFreeMarkerTemplateDef)templateDef).getFreeMarkerTemplate().process(map, out);
				} finally {
					if(out!=null)try{out.flush();}catch(Exception e){}
					if(out!=null) out.close();
				}	
				
			}
		}else{
			String fileName = templateDef.getSourceFileNamePrefix()			
			+ templateDef.getSourceFileNameSuffix()
			+ templateDef.getSourceFileNameExtension();				
			File javaSourceFile = new File(templateDef.getOutputDirectory(), fileName);				
			log.info("Generating file " + javaSourceFile.getCanonicalPath());
			map.put("entities", entities);				
			FileWriter out = null;			 
			try {
				out = new FileWriter(javaSourceFile);
				((BuiltInFreeMarkerTemplateDef)templateDef).getFreeMarkerTemplate().process(map, out);
			} finally {
				if(out!=null)try{out.flush();}catch(Exception e){}
				if(out!=null) out.close();
			}			
		}
	}

	protected Map<String, Object> getFreeMarkerMap()
	{
		Map<String, Object> map = new HashMap<String, Object>();		
		map.put("appConfig", this.appConfig);		
		return map;
	}	
	
	
	public String getVersion() {
		
		if(!StringUtils.isEmpty(properties.getProperty(VERSION)))
		{
				return properties.getProperty(VERSION).trim();
		}	
		return version;
	}

	public void setVersion(String version) {
		this.version = version;
	}

	public String getGroupId() 
	{
		if(!StringUtils.isEmpty(properties.getProperty(GROUPID)))
		{
				return properties.getProperty(GROUPID).trim();
		}		
		return groupId;
	}

	public void setGroupId(String groupId) {
		this.groupId = groupId;
	}

	public String getOutputDirectory() 
	{
		if(!StringUtils.isEmpty(properties.getProperty(OUTPUT_DIRECTORY)))
		{
				return properties.getProperty(OUTPUT_DIRECTORY).trim();
		}	
		return outputDir;
	}

	public void setOutputDirectory(String outputDir) {
		this.outputDir = outputDir;
	}

	public String getArtifactId() 
	{
		if(!StringUtils.isEmpty(properties.getProperty(ARTIFACTID)))
		{
				return properties.getProperty(ARTIFACTID).trim();
		}
		return artifactId;
	}

	public void setArtifactId(String artifactId) {
		this.artifactId = artifactId;
	}

	public Properties getProperties() {
		return properties;
	}

	public void setProperties(Properties properties) {
		this.properties = properties;
	}

	public List<Entity> getEntities() {
		return entities;
	}
}
